//@author A0078695H
/**

System test

This system test applies test on the main logic class Taak.
It creates an instance of Taak and applies tests on Taak, 
simulating the process where user input strings.

The tests are grouped and very group contains a few test cases.

*/

#include "main.h"
#include "Taak.h"
#include "Parser.h"
#include "logger.hpp"

#include <time.h>

TEST(systemTest, init) {
	// Create and initialize Taak instance
	Taak taak;
	taak.initialize();

	// Should not throw any error
	EXPECT_NO_THROW(taak.getParser());
	EXPECT_NO_THROW(taak.displayHomePage());
}

TEST(systemTest, basicUtilityFunctions) {
	Taak taak;
	taak.initialize();
	// Basic display setters and getters. This systemTest does not cover GUI test
	// But it checks whether these GUI related API work
	taak.setMainDisplay("test message1");
	EXPECT_EQ(taak.getMainDisplay(), "test message1");

	taak.setStatusDisplay("test message2");
	EXPECT_EQ(taak.getStatusDisplay(), "test message2");

	taak.setInputDisplay("test message3");
	EXPECT_EQ(taak.getInputDisplay(), "test message3");

	taak.setMainDisplayTitle("test message4");
	EXPECT_EQ(taak.getMainDisplayTitle(), "test message4");

	vector<string> testStringVector;
	testStringVector.push_back("test message5");
	testStringVector.push_back("test message6");
	taak.setFeedbackDisplay(testStringVector);
	EXPECT_EQ(taak.getFeedbackDisplay(), testStringVector);
}


/**
Note: the MainSuccessScenarios test cases are compared in bulk, since no error is expected at all
*/
TEST(systemTest, basicCommandMainSuccessScenariosTypedInput) {
	ofstream file;
	file.open("output.txt", ios_base::trunc);
	Taak taak;
	taak.initialize();
	string res;

	// These are all most common, main success scenarios. They are expected to work flawlessly.
	if (file.is_open()) {
	// add scheduled
	res += taak.userInput("add test task1 tomorrow 9pm dec 27 3am");
	log(LOG_WARNING) << "add scheduled: " << res;

	// add deadlined
	res += taak.userInput("add test task2 november 12");
	log(LOG_WARNING) << "add deadlined: " << res;
	
	// add floating
	res += taak.userInput("add test task3");
	log(LOG_WARNING) << "add floating: " << res;

	// update
	res += taak.userInput("update 3 test task4");
	log(LOG_WARNING) << "update 3 test task4: " << res;

	// search by name
	// due to fuzzy search, task4 will appear on top
	res += taak.userInput("search task4");
	log(LOG_WARNING) << "search task4: " << res;

	// display
	res += taak.userInput("display");
	log(LOG_WARNING) << "display all: " << res;

	// sort
	res += taak.userInput("sort name desc");
	log(LOG_WARNING) << "sort: " << res;

	// del
	res += taak.userInput("delete 1");
	log(LOG_WARNING) << "del: " << res;

	// undo
	res += taak.userInput("undo");
	log(LOG_WARNING) << "undo: " << res;

	// done undone
	res += taak.userInput("done 1");
	log(LOG_WARNING) << "done 1: " << res;

	// filter
	res += taak.userInput("filter out nov 27");
	log(LOG_WARNING) << "filter out nov 27: " << res;

	// help
	res += taak.userInput("help");
	log(LOG_WARNING) << "help" << res;

	//// exit
	//EXPECT_EXIT(taak.userInput("exit"), 0, "");
	file << res;
	}
	file.close();
}

TEST(systemTest, basicCommandMainSuccessScenariosSuggestionInput) {
	Taak taak;
	taak.initialize();
	string res;
	ofstream file;
	file.open("output.txt", ios_base::app);
	// This is for userSuggestion input, where user type and the suggestions are generated
	// These are all most common, main success scenarios. They are expected to work flawlessly.
	if (file.is_open()) {
	// add scheduled
	res += taak.userCharInput("add test task1 tomorrow 9pm dec 27 3am");
	log(LOG_WARNING) << "add scheduled: " << res;

	// add deadlined
	res += taak.userCharInput("add test task2 november 12");
	log(LOG_WARNING) << "add deadlined: " << res;
	
	// add floating
	res += taak.userCharInput("add test task3");
	log(LOG_WARNING) << "add floating: " << res;

	// update
	res += taak.userCharInput("update 3 test task4");
	log(LOG_WARNING) << "update 3 test task4: " << res;

	// search by name
	// due to fuzzy search, task4 will appear on top
	res += taak.userCharInput("search task4");
	log(LOG_WARNING) << "search task4: " << res;

	// display
	res += taak.userCharInput("display");
	log(LOG_WARNING) << "display all: " << res;

	// sort
	res += taak.userCharInput("sort name desc");
	log(LOG_WARNING) << "sort: " << res;

	// del
	res += taak.userCharInput("delete 1");
	log(LOG_WARNING) << "del: " << res;

	// undo
	res += taak.userCharInput("undo");
	log(LOG_WARNING) << "undo: " << res;

	// done undone
	res += taak.userCharInput("done 1");
	log(LOG_WARNING) << "done 1: " << res;

	// filter
	res += taak.userCharInput("filter out nov 27");
	log(LOG_WARNING) << "filter out nov 27: " << res;

	// help
	res += taak.userCharInput("help");
	log(LOG_WARNING) << "help" << res;

	//// exit
	//EXPECT_EXIT(taak.userCharInput("exit"), 0, "");
	file << res;
	}
	file.close();
}

//@author A0096566M
// the following are edge cases testing. 
// some cases are expected to give error prompt, while others are expected to 
// execute with no error
// it should not in any cases crash
TEST(systemTest, extremeCrashTests) {
	//Extreme tests to check if rubbish input would crash the system, and if they are handled properly.
	//Expect not to crash.
	Taak taak;
	taak.initialize();
	string res = "";
	ofstream file;
	file.open("output.txt", ios_base::app);
	if (file.is_open()) {
		//Tests on input
		res += taak.userInput("add ''''''");
		res += taak.userInput("'add' \"\"\"");
		res += taak.userInput("add <br>>><<");
		res += taak.userInput("delete 1-3, 2-4, 1-7");
	
		res +=taak.userInput("delete ab1-4 5-7");
		res +=taak.userInput("done -1");
		res +=taak.userInput("done 0");
		res +=taak.userInput("done -1--3");
		res +=taak.userInput("done 1--3");
		res +=taak.userInput("clear");
		res +=taak.userInput("");
		res +=taak.userInput("add    rubbish   input   ");
		res +=taak.userInput(" delete  -1 ");
		res +=taak.userInput("done abcde");
		res +=taak.userInput("done 12");
		res +=taak.userInput("done ab");
		//This test case will never happen, because UI should have escaped html chaacters before calling this.
		//Test is just to check if it will crash.
		res +=taak.userInput("add <html?> <br> <<<<   >>  ");	
		res +=taak.userInput("add today tomorrow yesterday");
		res +=taak.userInput("add the day after tomorrow");
		res +=taak.userInput("add practise yesterday once more");
		res +=taak.userInput("add today tomorrow yesterday friday next monday happy new year");
		res +=taak.userInput("add ~!@#$%^&*()_+=");
		res +=taak.userInput("add &nbsp; &&&&& hello");
		res +=taak.userInput("add ##### today tomorrow yesterday# #frida#y #next ###mond#ay happy new year");
		res +=taak.userInput("done 1-3 2-5  -1-1- ");
		res +=taak.userInput("delete - - 1 2 3");
		res +=taak.userInput("update   1   hello");

		//Test suggestions system
		res +=taak.userCharInput("clear");
		res +=taak.userCharInput("");
		res +=taak.userCharInput("add    rubbish   input   ");
		res +=taak.userCharInput(" delete  -1 ");
		res +=taak.userCharInput("done abcde");
		res +=taak.userCharInput("done 12");
		res +=taak.userCharInput("done ab");
		res +=taak.userCharInput("add <html?> <br> <<<<   >>  ");
		res +=taak.userCharInput("add today tomorrow yesterday");
		res +=taak.userCharInput("add ~!@#$%^&*()_+=");
		res +=taak.userCharInput("add &nbsp; &&&&& hello");

		file << res;
	}
	file.close();
}
//@author A0078695H
// read output.txt and asserts that it equals to expectedOutput.txt
TEST(systemTest, wrapSystemTest) {
	ifstream expected;
	ifstream output;
	expected.open("expectedOutput.txt");
	output.open("output.txt");
	ASSERT_TRUE(expected.is_open());
	ASSERT_TRUE(expected.is_open());

	char buffer[200000];
	int count;
	count = expected.read(buffer, 200000).gcount();
	string expectedString = string(buffer, buffer+count);
	count = output.read(buffer, 200000).gcount();
	string outputString = string(buffer, buffer+count);
	expected.close();
	output.close();
	ASSERT_TRUE(outputString == expectedString);
	
	
	// Since the above test is an assert
	// when it's not true, test will terminate and devs are to investigate output.txt and expectedOutput.txt
	// when it's true, test succeeded. Flush the content of output.txt
	ofstream flushOutput;
	flushOutput.open("output.txt");
	flushOutput.close();
}